package services

import (
	"bytes"
	"encoding/json"
	"fmt"
	"io"
	"net/http"
	"time"

	"jianianhua-server/config"
	"jianianhua-server/database"
	"jianianhua-server/models"
)

// WechatMessageService 微信消息服务
type WechatMessageService struct {
	config *config.Config
}

// NewWechatMessageService 创建微信消息服务
func NewWechatMessageService(cfg *config.Config) *WechatMessageService {
	return &WechatMessageService{
		config: cfg,
	}
}

// SubscribeMessageData 订阅消息数据结构
type SubscribeMessageData struct {
	TemplateID string                 `json:"template_id"`
	Page       string                 `json:"page"`
	Data       map[string]interface{} `json:"data"`
}

// SendSubscribeMessage 发送订阅消息（带重试机制）
func (s *WechatMessageService) SendSubscribeMessage(openID, templateID, page string, data map[string]interface{}) error {
	const maxRetries = 20        // 最大重试次数
	const initialDelay = 2       // 初始延迟时间（秒）
	const maxDelay = 60          // 最大延迟时间（秒）
	
	var lastErr error
	
	for attempt := 1; attempt <= maxRetries; attempt++ {
		// 获取access_token
		accessToken, err := s.getAccessToken()
		if err != nil {
			lastErr = fmt.Errorf("获取access_token失败: %v", err)
			fmt.Printf("⚠️  [重试 %d/%d] %v\n", attempt, maxRetries, lastErr)
			if attempt < maxRetries {
				delay := s.calculateRetryDelay(attempt, initialDelay, maxDelay)
				fmt.Printf("⏳ 等待 %d 秒后重试...\n", delay)
				time.Sleep(time.Duration(delay) * time.Second)
			}
			continue
		}

		// 发送请求
		url := fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/message/subscribe/send?access_token=%s", accessToken)
		requestBody := map[string]interface{}{
			"touser":      openID,
			"template_id": templateID,
			"page":        page,
			"data":        data,
		}
		jsonData, err := json.Marshal(requestBody)
		if err != nil {
			lastErr = fmt.Errorf("序列化请求数据失败: %v", err)
			fmt.Printf("⚠️  [重试 %d/%d] %v\n", attempt, maxRetries, lastErr)
			if attempt < maxRetries {
				delay := s.calculateRetryDelay(attempt, initialDelay, maxDelay)
				fmt.Printf("⏳ 等待 %d 秒后重试...\n", delay)
				time.Sleep(time.Duration(delay) * time.Second)
			}
			continue
		}

		if attempt == 1 {
			fmt.Printf("📨 发送订阅消息请求 - URL: %s, 请求体: %s\n", url, string(jsonData))
		} else {
			fmt.Printf("🔄 [重试 %d/%d] 重新发送订阅消息请求\n", attempt, maxRetries)
		}

		resp, err := http.Post(url, "application/json", bytes.NewBuffer(jsonData))
		if err != nil {
			lastErr = fmt.Errorf("发送请求失败: %v", err)
			fmt.Printf("⚠️  [重试 %d/%d] %v\n", attempt, maxRetries, lastErr)
			if attempt < maxRetries {
				delay := s.calculateRetryDelay(attempt, initialDelay, maxDelay)
				fmt.Printf("⏳ 等待 %d 秒后重试...\n", delay)
				time.Sleep(time.Duration(delay) * time.Second)
			}
			continue
		}
		defer resp.Body.Close()

		body, err := io.ReadAll(resp.Body)
		if err != nil {
			lastErr = fmt.Errorf("读取响应失败: %v", err)
			fmt.Printf("⚠️  [重试 %d/%d] %v\n", attempt, maxRetries, lastErr)
			if attempt < maxRetries {
				delay := s.calculateRetryDelay(attempt, initialDelay, maxDelay)
				fmt.Printf("⏳ 等待 %d 秒后重试...\n", delay)
				time.Sleep(time.Duration(delay) * time.Second)
			}
			continue
		}

		// 解析响应
		var result map[string]interface{}
		if err := json.Unmarshal(body, &result); err != nil {
			lastErr = fmt.Errorf("解析响应失败: %v", err)
			fmt.Printf("⚠️  [重试 %d/%d] %v\n", attempt, maxRetries, lastErr)
			if attempt < maxRetries {
				delay := s.calculateRetryDelay(attempt, initialDelay, maxDelay)
				fmt.Printf("⏳ 等待 %d 秒后重试...\n", delay)
				time.Sleep(time.Duration(delay) * time.Second)
			}
			continue
		}

		// 检查是否成功
		if errcode, ok := result["errcode"].(float64); ok && errcode != 0 {
			errmsg := ""
			if msg, ok := result["errmsg"].(string); ok {
				errmsg = msg
			}
			
			// 某些错误不应该重试（如参数错误、用户拒绝等）
			if s.isNonRetryableError(errcode) {
				lastErr = fmt.Errorf("微信API错误 (errcode: %.0f, errmsg: %s): %v", errcode, errmsg, result)
				fmt.Printf("❌ 不可重试的错误 - errcode: %.0f, errmsg: %s\n", errcode, errmsg)
				return lastErr
			}
			
			lastErr = fmt.Errorf("微信API错误 (errcode: %.0f, errmsg: %s): %v", errcode, errmsg, result)
			fmt.Printf("⚠️  [重试 %d/%d] 微信API返回错误 - errcode: %.0f, errmsg: %s\n", attempt, maxRetries, errcode, errmsg)
			
			if attempt < maxRetries {
				delay := s.calculateRetryDelay(attempt, initialDelay, maxDelay)
				fmt.Printf("⏳ 等待 %d 秒后重试...\n", delay)
				time.Sleep(time.Duration(delay) * time.Second)
			}
			continue
		}

		// 发送成功
		if attempt > 1 {
			fmt.Printf("✅ [重试成功] 微信订阅消息发送成功 - OpenID: %s, 模板ID: %s, 重试次数: %d\n", openID, templateID, attempt-1)
		} else {
			fmt.Printf("✅ 微信订阅消息发送成功 - OpenID: %s, 模板ID: %s\n", openID, templateID)
		}
		return nil
	}

	// 所有重试都失败了
	fmt.Printf("❌ 发送订阅消息失败，已重试 %d 次 - OpenID: %s, 模板ID: %s, 最后错误: %v\n", maxRetries, openID, templateID, lastErr)
	return fmt.Errorf("发送订阅消息失败，已重试 %d 次: %v", maxRetries, lastErr)
}

// calculateRetryDelay 计算重试延迟时间（指数退避策略）
func (s *WechatMessageService) calculateRetryDelay(attempt, initialDelay, maxDelay int) int {
	// 指数退避：2^attempt * initialDelay，但不超过 maxDelay
	delay := initialDelay * (1 << (attempt - 1))
	if delay > maxDelay {
		delay = maxDelay
	}
	return delay
}

// isNonRetryableError 判断是否为不可重试的错误
func (s *WechatMessageService) isNonRetryableError(errcode float64) bool {
	// 这些错误不应该重试：
	// 40037: template_id不正确
	// 43101: 用户拒绝接受消息
	// 47003: argument is invalid
	nonRetryableCodes := []float64{40037, 43101, 47003}
	for _, code := range nonRetryableCodes {
		if errcode == code {
			return true
		}
	}
	return false
}

// getAccessToken 获取微信access_token
func (s *WechatMessageService) getAccessToken() (string, error) {
	// 构建请求URL
	url := fmt.Sprintf("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=%s&secret=%s",
		s.config.WechatAppID, s.config.WechatSecret)

	// 发送请求
	resp, err := http.Get(url)
	if err != nil {
		return "", fmt.Errorf("请求access_token失败: %v", err)
	}
	defer resp.Body.Close()

	// 读取响应
	body, err := io.ReadAll(resp.Body)
	if err != nil {
		return "", fmt.Errorf("读取响应失败: %v", err)
	}

	// 解析响应
	var result map[string]interface{}
	if err := json.Unmarshal(body, &result); err != nil {
		return "", fmt.Errorf("解析响应失败: %v", err)
	}

	// 检查是否有错误
	if errcode, ok := result["errcode"].(float64); ok && errcode != 0 {
		return "", fmt.Errorf("微信API错误: %v", result)
	}

	// 获取access_token
	accessToken, ok := result["access_token"].(string)
	if !ok {
		return "", fmt.Errorf("access_token格式错误")
	}

	return accessToken, nil
}

// SendCancelNotification 发送取消预约通知（管理员取消订单时发送给用户）
func (s *WechatMessageService) SendCancelNotification(appointment *models.Appointment, reason string) error {
	fmt.Printf("📧 [取消通知] 开始发送取消预约通知给用户\n")
	fmt.Printf("📧 [取消通知] 预约信息 - ID: %d, 预约人: %s, 预约日期: %s, 预约时间: %s, 取消原因: %s\n",
		appointment.ID, appointment.CustomerName, appointment.AppointmentDate, appointment.AppointmentTime, reason)
	fmt.Printf("📧 [取消通知] 预约详情 - 预约项目: %s, 用户ID: %d, 顾客电话: %s\n",
		appointment.ProductTitle, appointment.UserID, appointment.CustomerPhone)

	// 获取用户信息
	var user models.User
	err := database.DB.Where("id = ?", appointment.UserID).First(&user).Error
	if err != nil {
		fmt.Printf("❌ [取消通知] 获取用户信息失败 - 用户ID: %d, 错误: %v\n", appointment.UserID, err)
		return fmt.Errorf("获取用户信息失败: %v", err)
	}

	fmt.Printf("✅ [取消通知] 查询到用户信息 - 用户ID: %d, 昵称: %s, OpenID: %s\n", 
		user.ID, user.Nickname, user.OpenID)

	if user.OpenID == "" {
		fmt.Printf("⚠️  [取消通知] 警告: 用户 ID=%d (昵称: %s) 没有 OpenID，跳过发送\n", user.ID, user.Nickname)
		return fmt.Errorf("用户没有 OpenID，无法发送消息")
	}

	// 确保字段值不为空，微信API不接受空值
	productTitle := appointment.ProductTitle
	if productTitle == "" {
		productTitle = "未指定"
	}
	customerName := appointment.CustomerName
	if customerName == "" {
		customerName = "未指定"
	}

	// 处理日期格式：确保是 YYYY-MM-DD 格式
	appointmentDate := appointment.AppointmentDate
	if appointmentDate == "" {
		appointmentDate = "未指定"
	} else {
		// 如果是 ISO 格式 (2025-11-06T00:00:00+08:00)，提取日期部分
		if len(appointmentDate) >= 10 {
			appointmentDate = appointmentDate[:10]
		}
	}

	// 处理预约时间格式：去掉秒部分，只保留 HH:MM
	appointmentTime := appointment.AppointmentTime
	if appointmentTime == "" {
		appointmentTime = "未指定"
	} else {
		// 如果是 HH:MM:SS 格式，只取前5位
		if len(appointmentTime) >= 5 {
			appointmentTime = appointmentTime[:5]
		}
	}

	// 处理联系方式
	phoneNumber := appointment.CustomerPhone
	if phoneNumber == "" {
		phoneNumber = "未提供"
	}

	// 构建消息数据（新模板格式）
	data := map[string]interface{}{
		"thing1": map[string]string{
			"value": productTitle, // 预约项目
		},
		"thing6": map[string]string{
			"value": customerName, // 预约人
		},
		"time7": map[string]string{
			"value": appointmentDate, // 预约日期
		},
		"time20": map[string]string{
			"value": appointmentTime, // 预约时间
		},
		"phone_number3": map[string]string{
			"value": phoneNumber, // 联系方式
		},
	}

	// 发送订阅消息
	templateID := "o7WljBjHOvNPXVvRdRO9pHFIOLO_pgbz3oc-WI4lng0" // 新模板ID
	page := "pages/appointmentManage/index"                     // 跳转到预约管理页面

	fmt.Printf("📤 [取消通知] 准备向用户发送取消通知 - 用户ID: %d, 昵称: %s, OpenID: %s\n",
		user.ID, user.Nickname, user.OpenID)
	fmt.Printf("📤 [取消通知] 消息模板 - 模板ID: %s, 跳转页面: %s\n", templateID, page)
	fmt.Printf("📤 [取消通知] 消息数据: %+v\n", data)

	err = s.SendSubscribeMessage(user.OpenID, templateID, page, data)
	if err != nil {
		fmt.Printf("❌ [取消通知] 向用户 %s (ID=%d) 发送取消通知失败: %v\n", user.Nickname, user.ID, err)
		return err
	}

	fmt.Printf("✅ [取消通知] 成功向用户 %s (ID=%d) 发送取消预约通知 - 预约ID: %d, 预约人: %s\n", 
		user.Nickname, user.ID, appointment.ID, appointment.CustomerName)
	return nil
}

// SendCancelNotificationToAdmins 向所有管理员发送取消预约通知
func (s *WechatMessageService) SendCancelNotificationToAdmins(appointment *models.Appointment) error {
	fmt.Printf("📧 开始发送取消预约通知给管理员 - 预约ID: %d, 预约人: %s, 预约日期: %s, 预约时间: %s\n",
		appointment.ID, appointment.CustomerName, appointment.AppointmentDate, appointment.AppointmentTime)

	// 获取所有管理员（role = 'admin'）
	var admins []models.User
	err := database.DB.Where("role = ?", "admin").Find(&admins).Error
	if err != nil {
		return fmt.Errorf("获取管理员列表失败: %v", err)
	}

	if len(admins) == 0 {
		fmt.Println("⚠️  警告: 没有找到管理员用户，无法发送取消预约通知")
		return nil
	}

	fmt.Printf("📋 找到 %d 个管理员\n", len(admins))

	// 确保字段值不为空，微信API不接受空值
	productTitle := appointment.ProductTitle
	if productTitle == "" {
		productTitle = "未指定"
	}
	customerName := appointment.CustomerName
	if customerName == "" {
		customerName = "未指定"
	}

	// 处理日期格式：确保是 YYYY-MM-DD 格式
	appointmentDate := appointment.AppointmentDate
	if appointmentDate == "" {
		appointmentDate = "未指定"
	} else {
		// 如果是 ISO 格式 (2025-11-06T00:00:00+08:00)，提取日期部分
		if len(appointmentDate) >= 10 {
			appointmentDate = appointmentDate[:10]
		}
	}

	// 处理预约时间格式：去掉秒部分，只保留 HH:MM
	appointmentTime := appointment.AppointmentTime
	if appointmentTime == "" {
		appointmentTime = "未指定"
	} else {
		// 如果是 HH:MM:SS 格式，只取前5位
		if len(appointmentTime) >= 5 {
			appointmentTime = appointmentTime[:5]
		}
	}

	// 处理联系方式
	phoneNumber := appointment.CustomerPhone
	if phoneNumber == "" {
		phoneNumber = "未提供"
	}

	// 构建消息数据（取消订单模板格式）
	data := map[string]interface{}{
		"thing1": map[string]string{
			"value": productTitle, // 预约项目
		},
		"thing6": map[string]string{
			"value": customerName, // 预约人
		},
		"time7": map[string]string{
			"value": appointmentDate, // 预约日期
		},
		"time20": map[string]string{
			"value": appointmentTime, // 预约时间
		},
		"phone_number3": map[string]string{
			"value": phoneNumber, // 联系方式
		},
	}

	// 模板ID
	templateID := "o7WljBjHOvNPXVvRdRO9pHFIOLO_pgbz3oc-WI4lng0"
	page := "pages/appointmentManage/index" // 跳转到预约管理页面

	// 向所有管理员发送消息
	var errors []string
	var successCount int
	for _, admin := range admins {
		fmt.Printf("📤 准备向管理员发送取消通知 - ID: %d, 昵称: %s, OpenID: %s\n",
			admin.ID, admin.Nickname, admin.OpenID)

		if admin.OpenID == "" {
			fmt.Printf("⚠️  警告: 管理员 ID=%d (昵称: %s) 没有 OpenID，跳过发送\n", admin.ID, admin.Nickname)
			continue
		}

		err := s.SendSubscribeMessage(admin.OpenID, templateID, page, data)
		if err != nil {
			errorMsg := fmt.Sprintf("向管理员 %s (ID=%d) 发送取消通知失败: %v", admin.Nickname, admin.ID, err)
			fmt.Printf("❌ %s\n", errorMsg)
			errors = append(errors, errorMsg)
			// 继续发送给其他管理员，不中断流程
		} else {
			fmt.Printf("✅ 成功向管理员 %s (ID=%d) 发送取消预约通知\n", admin.Nickname, admin.ID)
			successCount++
		}
	}

	fmt.Printf("📊 发送结果 - 成功: %d/%d, 失败: %d\n", successCount, len(admins), len(errors))

	// 如果有部分发送失败，返回错误但不影响主流程
	if len(errors) > 0 && len(errors) == len(admins) {
		// 如果所有管理员都发送失败，才返回错误
		return fmt.Errorf("所有管理员消息发送失败: %v", errors)
	}

	return nil
}

// SendAppointmentNotificationToAdmins 向所有管理员发送预约通知
func (s *WechatMessageService) SendAppointmentNotificationToAdmins(appointment *models.Appointment) error {
	fmt.Printf("📧 开始发送预约通知 - 预约ID: %d, 预约人: %s, 预约日期: %s, 预约时间: %s\n", 
		appointment.ID, appointment.CustomerName, appointment.AppointmentDate, appointment.AppointmentTime)

	// 获取所有管理员（role = 'admin'）
	var admins []models.User
	err := database.DB.Where("role = ?", "admin").Find(&admins).Error
	if err != nil {
		return fmt.Errorf("获取管理员列表失败: %v", err)
	}

	if len(admins) == 0 {
		// 如果没有管理员，记录日志但不报错
		fmt.Println("⚠️  警告: 没有找到管理员用户，无法发送预约通知")
		return nil
	}

	fmt.Printf("📋 找到 %d 个管理员\n", len(admins))

	// 确保字段值不为空，微信API不接受空值
	productTitle := appointment.ProductTitle
	if productTitle == "" {
		productTitle = "未指定"
	}
	customerName := appointment.CustomerName
	if customerName == "" {
		customerName = "未指定"
	}
	
	// 处理日期格式：确保是 YYYY-MM-DD 格式
	appointmentDate := appointment.AppointmentDate
	if appointmentDate == "" {
		appointmentDate = "未指定"
	} else {
		// 如果是 ISO 格式 (2025-11-06T00:00:00+08:00)，提取日期部分
		if len(appointmentDate) >= 10 {
			appointmentDate = appointmentDate[:10]
		}
	}
	
	// 处理预约时间格式：去掉秒部分，只保留 HH:MM
	appointmentTime := appointment.AppointmentTime
	if appointmentTime == "" {
		appointmentTime = "未指定"
	} else {
		// 如果是 HH:MM:SS 格式，只取前5位
		if len(appointmentTime) >= 5 {
			appointmentTime = appointmentTime[:5]
		}
	}

	// 处理联系方式
	phoneNumber := appointment.CustomerPhone
	if phoneNumber == "" {
		phoneNumber = "未提供"
	}

	fmt.Printf("📝 消息内容 - 预约项目: %s, 预约人: %s, 到店日期: %s, 预约时间: %s, 联系方式: %s\n",
		productTitle, customerName, appointmentDate, appointmentTime, phoneNumber)

	// 构建消息数据（新模板格式）
	data := map[string]interface{}{
		"thing9": map[string]string{
			"value": productTitle, // 预约项目
		},
		"thing1": map[string]string{
			"value": customerName, // 预约人
		},
		"time6": map[string]string{
			"value": appointmentDate, // 到店日期
		},
		"time2": map[string]string{
			"value": appointmentTime, // 预约时间
		},
		"phone_number16": map[string]string{
			"value": phoneNumber, // 联系方式
		},
	}

	// 模板ID
	templateID := "ktex3oGhX7Bp8heWLu5dM10pRwXvtrQHEIkHNcNVGAQ"
	page := "pages/appointmentManage/index" // 跳转到预约管理页面

	// 向所有管理员发送消息
	var errors []string
	var successCount int
	for _, admin := range admins {
		fmt.Printf("📤 准备向管理员发送消息 - ID: %d, 昵称: %s, OpenID: %s\n", 
			admin.ID, admin.Nickname, admin.OpenID)
		
		if admin.OpenID == "" {
			fmt.Printf("⚠️  警告: 管理员 ID=%d (昵称: %s) 没有 OpenID，跳过发送\n", admin.ID, admin.Nickname)
			continue
		}

		err := s.SendSubscribeMessage(admin.OpenID, templateID, page, data)
		if err != nil {
			errorMsg := fmt.Sprintf("向管理员 %s (ID=%d) 发送消息失败: %v", admin.Nickname, admin.ID, err)
			fmt.Printf("❌ %s\n", errorMsg)
			errors = append(errors, errorMsg)
			// 继续发送给其他管理员，不中断流程
		} else {
			fmt.Printf("✅ 成功向管理员 %s (ID=%d) 发送预约通知\n", admin.Nickname, admin.ID)
			successCount++
		}
	}

	fmt.Printf("📊 发送结果 - 成功: %d/%d, 失败: %d\n", successCount, len(admins), len(errors))

	// 如果有部分发送失败，返回错误但不影响主流程
	if len(errors) > 0 && len(errors) == len(admins) {
		// 如果所有管理员都发送失败，才返回错误
		return fmt.Errorf("所有管理员消息发送失败: %v", errors)
	}

	return nil
}
